﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Windows.Forms;
using System.Diagnostics;

namespace Launcher
{
    partial class Launcher : Form
    {
        #region global variables
        public int returnStatus = 0;
        public bool showSplashScreen;
        public List<String> skipFileList;
        public List<String> skipDirectoryList;
        public Process splashScreen;
        public String PackageName;
        public String LogDirectory = @"C:\windows\General Mills, Inc\2.0";
        public String LogPath;
        public Process parentProcess;
        public List<Command> commandList;
        #endregion

        public Launcher(List<Command> commandList, String PackageName)
        {
            InitializeComponent();
            this.Text = PackageName + " Installer";
            this.WindowState = FormWindowState.Maximized;
            this.PackageName = PackageName;
            this.commandList = commandList;
        }


        #region Skip File Functions
        public bool checkSkipFiles()
        {
            bool configStatus = true;

            foreach (String skipFileLocation in skipFileList)
            {
                configStatus = !(File.Exists(skipFileLocation));
                if (configStatus == false) { break; }
            }
            if (configStatus)
            {
                foreach (String skipDirectoryLocation in skipDirectoryList)
                {
                    configStatus = !(Directory.Exists(skipDirectoryLocation));
                    if (configStatus == false) { break; }
                }
            }

            return configStatus;
        }
        #endregion
        #region loggingMethods
        public void startLog()
        {
            LogPath = Path.Combine(LogDirectory, PackageName + ".log");

            addHeaderInfo();
            addProcessInfo();
        }
        public void addHeaderInfo()
        {
            try
            {
                if (!Directory.Exists(LogDirectory)) { Directory.CreateDirectory(LogDirectory); }
                if (File.Exists(LogPath))
                {
                    using (StreamWriter sw = File.AppendText(LogPath))
                    {
                        try { sw.WriteLine("################################################################################"); }
                        catch { }
                        try { sw.WriteLine("--------------------------------------------------------------------------------"); }
                        catch { }
                        try { sw.WriteLine("Package Name:           " + PackageName); }
                        catch { }
                        try { sw.WriteLine("Machine Name:           " + System.Environment.MachineName.ToString()); }
                        catch { }
                        try { sw.WriteLine("Date:                   " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString()); }
                        catch { }
                        try { sw.WriteLine("Launching Application:  " + parentProcess.ProcessName); }
                        catch { }
                        try { sw.WriteLine("Launching User:         " + WindowsIdentity.GetCurrent().Name); }
                        catch { }
                        try
                        {
                            PerformanceCounter upTime = new PerformanceCounter("System", "System Up Time");
                            upTime.NextValue();
                            TimeSpan ts = TimeSpan.FromSeconds(upTime.NextValue());
                            sw.WriteLine("System Uptime:          {0}d {1}h {2}m {3}s", ts.Days, ts.Hours, ts.Minutes, ts.Seconds);
                        }
                        catch { }
                        try { sw.WriteLine("--------------------------------------------------------------------------------"); }
                        catch { }
                    }
                }
                else
                {
                    using (StreamWriter sw = File.AppendText(LogPath))
                    {
                        try { sw.WriteLine("################################################################################"); }
                        catch { }
                        try { sw.WriteLine("--------------------------------------------------------------------------------"); }
                        catch { }
                        try { sw.WriteLine("Package Name:           " + PackageName); }
                        catch { }
                        try { sw.WriteLine("Machine Name:           " + System.Environment.MachineName.ToString()); }
                        catch { }
                        try { sw.WriteLine("Date:                   " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString()); }
                        catch { }
                        try { sw.WriteLine("Launching Application:  " + parentProcess.ProcessName); }
                        catch { }
                        try { sw.WriteLine("Launching User:         " + WindowsIdentity.GetCurrent().Name); }
                        catch { }
                        try
                        {
                            PerformanceCounter upTime = new PerformanceCounter("System", "System Up Time");
                            upTime.NextValue();
                            TimeSpan ts = TimeSpan.FromSeconds(upTime.NextValue());
                            sw.WriteLine("System Uptime:          {0}d {1}h {2}m {3}s", ts.Days, ts.Hours, ts.Minutes, ts.Seconds);
                        }
                        catch { }
                        try { sw.WriteLine("--------------------------------------------------------------------------------"); }
                        catch { }
                    }
                }
            }
            catch (Exception ex) { }
        }
        public void addProcessInfo()
        {
            Process[] allProcesses = Process.GetProcesses();

            using (StreamWriter sw = File.AppendText(LogPath))
            {
                sw.WriteLine("--------------------------------------------------------------------------------");
                foreach (Process proc in allProcesses)
                {
                    sw.WriteLine("Process Image Name:   " + proc.ProcessName.ToString());
                    try { sw.WriteLine("Process Description:  " + proc.MainModule.FileVersionInfo.FileDescription); }
                    catch { }
                    sw.WriteLine("");

                }
                sw.WriteLine("--------------------------------------------------------------------------------");
            }
        }
        private void LogProcessStart(Process p, bool runAsSystem)
        {
            using (StreamWriter sw = File.AppendText(LogPath))
            {
                sw.WriteLine("--------------------------------------------------------------------------------");
                sw.WriteLine("Launcher is Starting: " + p.ProcessName);
                sw.WriteLine("Current Time:         " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString());
                sw.WriteLine("Aruments:             " + p.StartInfo.Arguments);
                sw.WriteLine("--------------------------------------------------------------------------------");
            }
        }
        private void LogProcessEnd(Process p)
        {
            using (StreamWriter sw = File.AppendText(LogPath))
            {
                sw.WriteLine("--------------------------------------------------------------------------------");
                sw.WriteLine("Process Has Finished: " + p.ProcessName);
                sw.WriteLine("Current Time:         " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString());
                sw.WriteLine("Process Exit Code:    " + p.ExitCode);
                sw.WriteLine("--------------------------------------------------------------------------------");
            }
        }
        private void LogInvalidEnvironment()
        {
            using (StreamWriter sw = File.AppendText(LogPath))
            {
                sw.WriteLine("--------------------------------------------------------------------------------");
                sw.WriteLine("Exiting Due to Invalid Parent Process (Not SCCM):  " + parentProcess.ProcessName);
                sw.WriteLine("--------------------------------------------------------------------------------");
            }
        }
        private void endLog()
        {
            using (StreamWriter sw = File.AppendText(LogPath))
            {
                sw.WriteLine("################################################################################");
            }
        }
        private void logError(Exception ex, Command c)
        {
            using (StreamWriter sw = File.AppendText(LogPath))
            {
                sw.WriteLine("--------------------------------------------------------------------------------");
                sw.WriteLine("Launcher encountered an Error with Command " + c.Executable + " Arguments " + c.Arguments + ":  " + ex.Message.ToString());
                sw.WriteLine("--------------------------------------------------------------------------------");
            }
        }
        #endregion
        #region command Functions
        public int runCommands(List<Command> commandList)
        {
            int returnCode = 0;

            foreach (Command command in commandList)
            {
                String processorArch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
                ProcessStartInfo psi = new ProcessStartInfo();

                String argString = String.Empty;

                foreach (string arg in command.Arguments)
                {
                    if (argString == String.Empty) { argString = arg; }
                    else { argString += " " + arg; }
                }

                psi.Arguments = argString;
                psi.FileName = command.Executable;

                Process p = new Process();

                p.StartInfo = psi;

                switch (command.osArchitecture.ToUpper())
                {
                    case "32 BIT":
                        if (processorArch.Equals("x86"))
                        {
                            returnCode = runProcess(p, command);
                        }
                        break;
                    case "64 BIT":
                        if (processorArch.Equals("AMD64"))
                        {
                            returnCode = runProcess(p, command);
                        }
                        break;
                    case "ANY":
                        returnCode = runProcess(p, command);
                        break;
                    case "":

                        returnCode = runProcess(p, command);
                        break;
                    default:
                        returnCode = runProcess(p, command);
                        break;
                }

            }
            return returnCode;
        }
        private int runProcess(Process p, Command command)
        {
            int returnCode = 0;

            try
            {
                p.Start();
                LogProcessStart(p, command.runAsAdmin);
                try
                {
                    p.WaitForInputIdle();
                    if (command.killOnIdle)
                    {
                        p.Kill();
                    }
                }
                catch { }

                if (command.WaitForExit) { p.WaitForExit(); LogProcessEnd(p); }
                if (command.returnExitCode) { returnCode = p.ExitCode; }
            }
            catch (Exception ex)
            {
                logError(ex, command);
            }
            return returnCode;
        }
        #endregion

        private void Launcher_Activated(object sender, EventArgs e)
        {
        }

        private void Launcher_Shown(object sender, EventArgs e)
        {
            startLog();
            returnStatus = runCommands(commandList);
            endLog();
            this.Close();
        }
    }
}
